//
// file.c
// loading code and data from files
//
// (c) 2008 why the lucky stiff, the freelance professor
//
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "potion.h"
#include "internal.h"

extern char **environ;

// 未使用 PN_MSG(potion_file_with, PN path) {
//   return PN_NIL;
// }

// 从标准输入读取一行字符串，或 nil 。
PN_MSG(potion_lobby_read) {
  const int linemax = 1024;
  char line[linemax];
  if (fgets(line, linemax, stdin) != NULL)
    return PN_STRING(line);
  clearerr(stdin); // 复位 EOF(ctrl-D)，否则造成 REPL 程序退出。
  return PN_NIL;
}

// 注册全局消息 Env 和 read 。
void potion_file_init(Potion *P) {
  // PN file_vt = PN_VTABLE(PN_TFILE);
  char **env = environ, *key;
  PN pe = potion_table_empty(P);
  while (*env != NULL) {
    for (key = *env; *key != '='; key++);
    potion_table_put(P, PN_NIL, pe, potion_str2(P, *env, key - *env),
      PN_STRING(key + 1));
    env++;
  }
  PN_DEF   (P->lobby, "Env",  pe);
  PN_METHOD(P->lobby, "read", potion_lobby_read, 0);
}

// 读取、返回文件全部内容，或 Error | PN_NIL(文件不存在)。
PN read_file(Potion *P, const char *filename) {
  PN buf = PN_NIL;
  const char *err = NULL;
  int fd = -1;
  struct stat stats;

  // 检查、打开、读取文件，失败则报错退出。
  if (stat(filename, &stats) == -1) {
    // err = "file %s does not exist.";
    // goto file_done;
    return PN_NIL;
  }

  fd = open(filename, O_RDONLY | O_BINARY);
  if (fd == -1) {
    err = "could not open %s. check permissions.";
    goto file_done;
  }

  buf = potion_bytes(P, stats.st_size);
  if (read(fd, PN_STR_PTR(buf), stats.st_size) != stats.st_size) {
    buf = PN_NIL;
    err = "could not read entire file %s.";
    goto file_done;
  }

  PN_STR_PTR(buf)[stats.st_size] = '\0';

  file_done:
  if (fd != -1) close(fd);
  if (err) {
    return ERROR(err, filename);
  }
  return buf;
}